﻿#pragma once


#include "../m_core/m_core.hpp"




class CPCLicense
{
public:
    /**
    *@brief     获取机器ID
    *@return    机器ID。成功后data存储的是机器id，errdesc存储的是逻辑过程。失败后data为空，errdesc存储的是失败原因。
    *@remark    逻辑过程：
    *           1.取网卡列表
    *           2.获取网卡列表中的有限物理网卡列表。如果有，则取最大的物理网卡MAC；
    *             否则，取所有网卡中的最大MAC
    *           3.把第二步的值转化为HEX
    */
    static CPCResult<std::string> GetDeviceIDWithMac()
    {
        CPCResult<std::string> ret;
        std::vector<StNetAdapter> vecInfo;
        auto retNets = CPCNetUtil::PCGetNetAdapterInfo(vecInfo);
        if (!retNets)
        {
            return ret.SetFail("Enum NetAdapters Fail:%s", retNets.ErrDesc());
        }
        if (vecInfo.size() == 0)
        {
            return ret.SetFail("NetAdapters is empty");
        }

        //找出所有的物理有线网卡中最大的MAC
        std::string log;
        std::string maxMac;
        for (auto it = vecInfo.begin(); it != vecInfo.end(); ++it)
        {
            std::string tmp = CPCStrUtil::ShortFormat("[TYPE:%d][IP:%s][MAC:%s][NAME::%s]\r\n", it->type, it->szIp, it->szMac, it->szName);
            log += tmp;

            if (it->type == 1 && strcmp( it->szMac ,maxMac.c_str() ) > 0)
            {
                maxMac = it->szMac;
            }
        }

        //如果没有物理有线网卡，直接使用所有网卡中最大的MAC
        if (maxMac.empty())
        {
            maxMac.clear();

            for (auto it = vecInfo.begin(); it != vecInfo.end(); ++it)
            {
                if (strcmp(it->szMac , maxMac.c_str()) >  0)
                {
                    maxMac = it->szMac;
                }
            }

            if (maxMac.empty())
            {
                return ret.SetFail("maxMac is empty");
            }
            log += "*[NOT FIND WIRED ADAPTER, GET ID FROM ALL ADAPTER]\r\n";
        }
        else
        {
            log += "*[FIND WIRED ADAPTER, GET ID FROM WIRED ADAPTER]\r\n";
        }
        std::string devid = CPCStrUtil::PCBytes2Dsp(maxMac.data(), maxMac.length());
        std::string tmp = CPCStrUtil::ShortFormat("*[CHOICE][MAC:%s][MAC-HEX:%s]", maxMac.c_str(), devid.c_str());
        log += tmp;
        return ret.SetSucc(std::move(devid), log);
    }

    /**
    *@brief     获取License
    *@param     devId   [in]    设备ID
    *@param     effDays [in]    license有效天数
    *@param     key     [in]    16字节密钥
    *@return    获取的license值
    */
    static CPCResult<std::string> GetLicenseByRequst(const char* devId, int effDays, const std::string& key)
    {
        CPCResult<std::string> ret;
        if (devId == NULL || devId[0] == 0)
        {
            return ret.SetFail("devId == NULL");
        }

        //生成请求json
        CPCJsonObject request;
        request.Set("/REQ", devId);

        //生效时间
        int64_t nowTimeMs = CPCTimeValue::Now().GetValue();
        request.Set("/STA", nowTimeMs);

        //过期时间
        if (effDays < 0)
        {
            //永久
            request.Set("/EXP", -1);
        }
        else
        {
            //限时
            int64_t ExpMs = nowTimeMs + (int64_t)effDays * 24LL * 3600LL * 1000LL;
            request.Set("/EXP", ExpMs);
        }
        auto retJson = request.Stringify();
        if (!retJson)
        {
            return ret.SetFail("Json Stringify Fail:%s", retJson.ErrDesc());
        }
        std::string reqStr = retJson.Take();
        
        //加密
        std::string res = CPC3DES::ECB(true, reqStr.data(), reqStr.length(), key.data(), key.length(), ePCPaddingModePKCS7);
        std::string resHex = CPCStrUtil::PCBytes2Dsp(res.data(), res.length());
        return ret.SetSucc(resHex);
    }

    /**
    *@brief     检查License
    *@param     license [in]    license
    *@param     key     [in]    16字节密钥
    *@return    license是否有效，有效时data输出到期时间
    */
    static CPCResult<std::string> CheckLicense(const char* license, const std::string& key)
    {
        CPCResult<std::string> ret;
        if (license == NULL)
        {
            return ret.SetFail("License is empty. \r\nTech Info:devId == NULL || license == NULL");
        }

        //先解密
        std::string resBytes = CPCStrUtil::PCDsp2Bytes(license);
        std::string resJson = CPC3DES::ECB(false, resBytes.data(), resBytes.length(), key.data(), key.length(), ePCPaddingModePKCS7);
        if (resJson.empty())
        {
            return ret.SetFail("Decrypt license failed, maybe license format error. \r\nTech Info:license[%s] ", license);
        }

        //再分析
        CPCJsonObject request;
        auto retParse = request.Parse(resJson.c_str());
        if (!retParse)
        {
            return ret.SetFail("Parse license failed, maybe license format error. \r\nTech Info:license[%s] Json[%s] Parse Fail:%s", license, resJson.c_str(), retParse.ErrDesc());
        }

        //核对devid
        auto retDevId = GetDeviceIDWithMac();
        if (!retDevId)
        {
            return ret.SetFail("Get device ID failed. \r\nTech Info:GetDeviceIDWithMac Fail:%s", retDevId.ErrDesc());
        }
        std::string DevIdLog = retDevId.ErrDesc();
        std::string DevId = retDevId.Take();
        std::string REQ = request.Get("/REQ", "");
        if (request.HasError())
        {
            return ret.SetFail("License error. Not find device ID. \r\nTech Info:license[%s] Json[%s] Get /REQ Fail:%s", license, resJson.c_str(), request.LastErrorInfo());
        }
        if (DevId != REQ)
        {
            return ret.SetFail("License error. This license does not belong to this machine. \r\nTech Info:license[%s] Json[%s] DevId[%s] != REQ[%s].\r\nDeviceIDLog:\r\n%s", license, resJson.c_str(), DevId.c_str(), REQ.c_str(), DevIdLog.c_str());
        }

        //获取过期时间
        int64_t EXPMs = request.Get("/EXP", (int64_t)0);
        if (request.HasError())
        {
            return ret.SetFail("License error. This license does not include an expiration time. \r\nTech Info:license[%s] Json[%s] Get /REQ Fail:%s", license, resJson.c_str(), request.LastErrorInfo());
        }

        //不是永久的license，还要核对是否过期
        std::string strExpiredTime;
        if (EXPMs >= 0)
        {
            strExpiredTime = CPCTimeValue(EXPMs).Format("%Y-%m-%d %H:%M:%S").Get();

            CPCTimeValue tvNow = CPCTimeValue::Now();
            int64_t nowValMs = tvNow.GetValue();
            if (nowValMs > EXPMs)
            {
                //已经过期
                auto retNowDesc = tvNow.Format("%Y-%m-%d %H:%M:%S").Get();
                return ret.SetFail("This license has expired. \r\nTech Info:license[%s] Json[%s] nowValMs[%lld=%s] > EXPMs[%lld=%s]", license, resJson.c_str(), nowValMs, retNowDesc.c_str(), EXPMs, strExpiredTime.c_str());
            }
        }
        else
        {
            strExpiredTime = "No expiration";
        }
        return ret.SetSucc(strExpiredTime);
    }

};



